package com.piece.blog.controller;

import com.piece.admin.api.dto.SysUserDTO;
import com.piece.admin.model.TbSysDict;
import com.piece.admin.model.TbSysUser;
import com.piece.admin.service.TbSysDictService;
import com.piece.admin.service.TbSysUserService;
import com.piece.admin.support.TranslateEntity;
import com.piece.admin.support.UserInfoSupport;
import com.piece.blog.event.ArticlePostEvent;
import com.piece.blog.model.Article;
import com.piece.blog.model.ArticleComment;
import com.piece.blog.model.ArticleInfo;
import com.piece.blog.service.ArticleCommentService;
import com.piece.blog.service.ArticleInfoService;
import com.piece.blog.service.ArticleService;
import com.piece.blog.service.ArticleTagService;
import com.piece.core.elasticsearch.support.EsSearchUtil;
import com.piece.core.framework.annotation.permission.AclPermission;
import com.piece.core.framework.annotation.permission.SubmitPermission;
import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.enums.sql.SqlKey;
import com.piece.core.framework.exception.PermissionException;
import com.piece.core.framework.exception.ServerException;
import com.piece.core.framework.support.bootstrap.DataTable;
import com.piece.core.framework.support.bootstrap.Order;
import com.piece.core.framework.support.bootstrap.QueryTable;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.support.dto.UserDetailDTO;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.util.basic.I18nUtil;
import com.piece.core.framework.util.object.BeanUtil;
import com.piece.core.framework.util.security.coder.AESCoder;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.web.controller.FrameWorkController;
import com.piece.member.model.UmsMember;
import com.piece.member.service.UmsMemberService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;

@Slf4j
@RestController
@Api(tags = {"博客前台管理"})
@RequestMapping("/public/blog")
public class BlogFrontController extends FrameWorkController {

    @Resource
    private TbSysUserService tbSysUserService;

    @Resource
    private UmsMemberService umsMemberService;

    @Resource
    private ArticleService articleService;

    @Resource
    private ArticleInfoService articleInfoService;

    @Resource
    private ArticleTagService tagService;

    @Resource
    private ArticleCommentService articleCommentService;

    @Resource
    private TbSysDictService tbSysDictService;

    @Autowired
    protected TranslateEntity translateEntity;

    @GetMapping("/center/{id}")
    @ApiOperation(value = "个人主页")
    @ApiImplicitParam(name = "id", value = "用户主键", type = "path")
    public AjaxResponse center(@PathVariable String id, UserDetailDTO userDetail) {
        try {
            Map<String, Object> modelMap = new HashMap<>();
            int userPosts = 0, userWatchers = 0, userWatched = 0;
            SysUserDTO user = null;
            if (null != userDetail) {
                user = (SysUserDTO) userDetail.getDetail();
            } else {
                TbSysUser user_ = tbSysUserService.findById(Convert.toLong(id));
                UserInfoSupport.setOtherInfo(user_);
                translateEntity.setEntityInfo(user_);
                user = new SysUserDTO();
                BeanUtil.copyProperties(user_, user, true);
            }
            // 获取发布的文章
            userPosts = articleService.countPostsByUser(user);
            // 获取被关注的人数
            userWatchers = articleService.countWatcherByUser(user);
            // 获取关注的人数
            userWatched = articleService.countWatchedByUser(user);

            modelMap.put("user", user);
            modelMap.put("userPosts", userPosts);
            modelMap.put("userWatchers", userWatchers);
            modelMap.put("userWatched", userWatched);
            return success(modelMap);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SERVER), e.getMessage());
        }
    }

    @GetMapping("/query/article/{id}")
    @ApiOperation(value = "查看文章详情")
    @ApiImplicitParam(name = "id", value = "文章主键", type = "path")
    public AjaxResponse queryArticle(@PathVariable String id, UserDetailDTO userDetail) throws Exception {
        Article article = articleService.findById(Convert.toLong(id));
        if (null == article) {
            throw new ServerException(I18nUtil.message(ExceptionConstants.NO_RESULT));
        }
        boolean isMine = false;
        if (null != userDetail && article.getCreateBy().equals(userDetail.getId())) {
            isMine = true;
        }

        // 非自己的隐私文件禁止查看
        if (!isMine && !StatusType.NORMAL.getCode().equals(article.getOpen())) {
            throw new ServerException(I18nUtil.message(ExceptionConstants.NO_RESULT));
        }

        SysUserDTO user = (SysUserDTO) userDetail.getDetail();
        // 是否已收藏
        boolean hasFavored = articleService.checkFavored(user, article.getArticleId());
        article.setHasFavored(hasFavored);
        // 是否已关注
        boolean hasWatched = articleService.checkWatched(user, Convert.toLong(article.getCreateBy()));
        article.setHasWatched(hasWatched);

        ArticleInfo info = articleInfoService.findByArticle(Convert.toLong(id));
        if (null != info && null != info.getContent()) {
            String content = info.getContent();
            article.setContent(content);
            article.setHtml(info.getHtml());
            // 查询文章组
            String group = article.getGroup();
            List<Article> groups_ = new ArrayList<>();
            if (StringUtil.isNotEmpty(group)) {
                List<Article> groups = articleService.findByGroup(group, article.getUser(), user);
                if (groups.size() > 0) {
                    int current = 0;
                    article.setCurrent(current);
                    for (Article article_: groups) {
                        if (article_.getArticleId().equals(article.getArticleId())) {
                            article_.setCurrent(1);
                            article.setCurrent(current++);
                        } else {
                            current++;
                        }
                        groups_.add(article_);
                    }
                }
            }
            article.setGroups(groups_);
        }

        String tags = article.getTags();
        if (StringUtil.isNotEmpty(tags)) {
            article.setTagsArr(Convert.toStrList(tags));
        } else {
            article.setTagsArr(new ArrayList<>());
        }

        TbSysUser createUser = tbSysUserService.findById(Convert.toLong(article.getCreateBy(), 0L));
        UserInfoSupport.setOtherInfo(createUser);
        translateEntity.setEntityInfo(createUser);
        SysUserDTO author = new SysUserDTO();
        BeanUtil.copyProperties(createUser, author, true);
        article.setUser(author);
        articleService.setOtherInfo(article);

        // 非加密文章推送阅读通知
        if (!isMine && StatusType.DELETE.getCode().equals(article.getCrypto())) {
            articleService.onPushEvent(article, ArticlePostEvent.ACTION_VIEW);
        } else if (StatusType.NORMAL.getCode().equals(article.getCrypto())) {
            if (isMine) {
                article.setCrypto(StatusType.DELETE.getCode());
                decryptArticle(article);
            } else {
                article.setContent("隐藏内容，无法查看");
                article.setHtml("隐藏内容，无法查看");
            }
        }

        // 查询评论
        List<ArticleComment> comments = articleCommentService.findByArticle(Convert.toLong(id));
        article.setComments(comments.size());
        article.setCommentList(comments);

        return success(article);
    }

    @AclPermission
    @GetMapping("/viewCrypto")
    @ApiOperation(value = "文章解密")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "文章主键"),
            @ApiImplicitParam(name = "salt", value = "分享码")
    })
    public AjaxResponse viewCrypto() {
        try {
            String id = getRequest().getParameter("id");
            String salt = getRequest().getParameter("salt");
            Article article = articleService.findById(Convert.toLong(id));
            String compare = article.getSalt();
            if (StringUtil.isEmpty(compare) || !compare.equals(salt)) {
                return error(I18nUtil.message("blog.share_code.error"));
            }
            ArticleInfo info = articleInfoService.findByArticle(Convert.toLong(id));
            if (null != info && !"4".equals(article.getChannel())) {
                article.setContent(info.getContent());
                article.setHtml(info.getHtml());
            }
            decryptArticle(article);
            setCopyright(article, article.getContent(), article.getHtml());
            articleService.onPushEvent(article, ArticlePostEvent.ACTION_VIEW);
            return success(article);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SERVER), e.getMessage());
        }
    }

    private void decryptArticle(Article article) throws Exception {
        String summary = article.getSummary();
        String content = article.getContent();
        String html = article.getHtml();
        summary = AESCoder.aesDecrypt(summary);
        content = AESCoder.aesDecrypt(content);
        html = AESCoder.aesDecrypt(html);

        if (StringUtil.isEmpty(content) || StringUtil.isEmpty(html)) {
            // 解密失败
            throw new PermissionException(I18nUtil.message("blog.permission.error"));
        }
        article.setSummary(summary);
        article.setContent(content);
        article.setHtml(html);
    }

    private void setCopyright(Article article, String content, String html) {
        if (!content.endsWith("本文归作者所有，未经作者允许，不得转载</p>")) {
            content += "<br/><p class=\"copyright\">注意：本文归作者所有，未经作者允许，不得转载</p>";
            html += "<br/><p class=\"copyright\">注意：本文归作者所有，未经作者允许，不得转载</p>";
            article.setContent(content);
            article.setHtml(html);
        }
    }

    @GetMapping("/loadVideo")
    @ApiOperation(value = "加载视频源")
    @ApiImplicitParam(name = "id", value = "文章主键")
    public AjaxResponse loadVideo() {
        try {
            long id = Convert.toLong(getRequest().getParameter("id"), 0L);
            ArticleInfo info = articleInfoService.findByArticle(id);
            return success(info.getContent());
        } catch (Exception e) {
            return error();
        }
    }

    @AclPermission
    @GetMapping("/hasWatch/{id}")
    @ApiOperation(value = "是否已关注用户")
    @ApiImplicitParam(name = "id", value = "用户主键", type = "path")
    public AjaxResponse hasWatch(@PathVariable String id, UserDetailDTO userDetail) {
        try {
            // 判断是否处于登陆状态
            if (userDetail.getId().equals(id)) {
                return error(I18nUtil.message("blog.watcher.error"), "不能关注自己！");
            }

            SysUserDTO user = (SysUserDTO) userDetail.getDetail();
            boolean hasWatch = articleService.hasWatch(user, Convert.toLong(id));
            return success(hasWatch);
        } catch (Exception e) {
            return error(I18nUtil.message("blog.watcher.error"), e.getMessage());
        }
    }

    @AclPermission
    @GetMapping("/watcher/{id}")
    @ApiOperation(value = "关注用户")
    @ApiImplicitParam(name = "id", value = "用户主键", type = "path")
    public AjaxResponse watcher(@PathVariable String id, UserDetailDTO userDetail) {
        try {
            // 判断是否处于登陆状态
            if (userDetail.getId().equals(id)) {
                return error(I18nUtil.message("blog.watcher.error"), "不能关注自己！");
            }

            SysUserDTO user = (SysUserDTO) userDetail.getDetail();
            int count = articleService.watcher(user, Convert.toLong(id));
            return success(count);
        } catch (Exception e) {
            return error(I18nUtil.message("blog.watcher.error"), e.getMessage());
        }
    }

    @AclPermission
    @GetMapping("/favor/{id}")
    @ApiOperation(value = "收藏文章")
    @ApiImplicitParam(name = "id", value = "文章主键", type = "path")
    public AjaxResponse favor(@PathVariable String id, UserDetailDTO userDetail) {
        try {
            // 判断是否处于登陆状态
            Article article = articleService.findById(Convert.toLong(id));
            if (userDetail.getId().equals(article.getCreateBy())) {
                return error(I18nUtil.message("blog.favor.error"), "不能收藏自己的文章！");
            }
            int count = articleService.favor(article, Convert.toLong(userDetail.getId()));
            return success(count);
        } catch (Exception e) {
            return error(I18nUtil.message("blog.favor.error"), e.getMessage());
        }
    }

    @GetMapping("/tag/list")
    @ApiOperation(value = "获取最热门标签")
    @ApiImplicitParam(name = "size", value = "标签数量")
    public AjaxResponse tagList() {
        try {
            // 获取发布的文章
            int size = Convert.toInt(getRequest().getParameter("size"), 20);
            QueryTable queryTable = new QueryTable();
            queryTable.setStart(0);
            queryTable.setLength(size);
            List<Order> orders = new ArrayList<>();
            orders.add(new Order("posts", SqlKey.DESC));
            queryTable.setOrder(orders);
            DataTable table = tagService.findPage(queryTable);
            return success(table.getData());
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SERVER), e.getMessage());
        }
    }

    @GetMapping("/dict/group")
    @ApiOperation(value = "查询博客分组列表")
    @ApiImplicitParam(name = "group", value = "分组名称")
    public AjaxResponse queryDicGroup() {
        try {
            String group = getRequest().getParameter("group");
            List<TbSysDict> groups = tbSysDictService.findByDicGroup(group);
            return success(groups);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SERVER), e.getMessage());
        }
    }

    @GetMapping("/query/channel")
    @ApiOperation(value = "查询文章类别")
    public AjaxResponse queryChannel() {
        try {
            List<TbSysDict> channels = tbSysDictService.findByDicGroup("blog_article_channel");
            return success(channels);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SERVER), e.getMessage());
        }
    }

    @GetMapping("/query/article")
    @ApiOperation(value = "查询文章列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "order", value = "排序"),
            @ApiImplicitParam(name = "channel", value = "栏目"),
            @ApiImplicitParam(name = "featured", value = "是否推荐"),
            @ApiImplicitParam(name = "tag", value = "标签"),
            @ApiImplicitParam(name = "author", value = "作者主键"),
            @ApiImplicitParam(name = "watcher", value = "关注人主键"),
            @ApiImplicitParam(name = "current_page", value = "当前页号"),
            @ApiImplicitParam(name = "page_length", value = "每页数量")
    })
    public AjaxResponse queryArticle(UserDetailDTO userDetail) {
        String order = Convert.toStr(getRequest().getParameter("order"), "newest");
        String channel = Convert.toStr(getRequest().getParameter("channel"));
        boolean featured = Convert.toBool(getRequest().getParameter("featured"), false);
        String tag = Convert.toStr(getRequest().getParameter("tag"));
        String author = Convert.toStr(getRequest().getParameter("author"));
        String watcher = Convert.toStr(getRequest().getParameter("watcher"));
        int currentPage = Convert.toInt(getRequest().getParameter("current_page"), 1);
        int length = Convert.toInt(getRequest().getParameter("page_length"), 15);
        List<Article> records = null;
        try {
            QueryTable queryTable = new QueryTable();
            queryTable.setCurrentPage(currentPage);
            queryTable.setLength(length);
            queryTable.setStart((queryTable.getCurrentPage() - 1) * queryTable.getLength());
            Map<String, Object> param = new HashMap<>();
            param.put("Q_status_S_EQ", StatusType.NORMAL.getCode());
            if (StringUtil.isNotEmpty(channel)) {
                param.put("Q_channel_S_EQ", channel);
            }
            if (StringUtil.isNotEmpty(tag)) {
                param.put("Q_tags_S_LK", tag);
            }
            if (featured) {
                param.put("Q_featured_S_EQ", StatusType.NORMAL.getCode());
            }

            SysUserDTO user = (SysUserDTO) userDetail.getDetail();
            // 判断相关权限
            if (null == userDetail) {
                param.put("Q_open_S_EQ", StatusType.VISIBLE.getCode());
                param.put("Q_memberLevel_INT_LE", 1);
            } else {
                UmsMember userMember = umsMemberService.findByUser(user.getUserId());
                param.put("Q_open_S_EQ_AND(group1)", StatusType.HIDDEN.getCode());
                param.put("Q_createBy_L_EQ_AND(group1)", userDetail.getId());
                param.put("Q_open_S_EQ_AND(group2)", StatusType.VISIBLE.getCode());
                param.put("Q_memberLevel_INT_LE_AND(group2)", null == userMember ? 1 : Convert.toInt(userMember.getLevelId(), 1));
            }
            // 发布的文章
            if (StringUtil.isNotEmpty(author)) {
                param.put("Q_createBy_L_EQ", Convert.toLong(author));
            }
            // 关注的文章
            if (StringUtil.isNotEmpty(watcher)) {
                TbSysUser user_ = tbSysUserService.findById(Convert.toLong(watcher));
                SysUserDTO watcherUser = new SysUserDTO();
                BeanUtil.copyProperties(user, user_, true);
                List<Long> watches = articleService.findWatchedByUser(watcherUser);
                if (null != watches && watches.size() > 0) {
                    param.put("Q_createBy_L_IN", watches);
                } else {
                    DataTable dataTable = new DataTable(queryTable);
                    dataTable.setData(new ArrayList());
                    dataTable.setRecordsTotal(0);
                    return success(dataTable);
                }
            }
            queryTable.setParams(param);
            List<Order> orders = new ArrayList<>();
            if ("favors".equals(order)) {
                orders.add(new Order("favors", SqlKey.DESC));
            } else if ("hottest".equals(order)) {
                orders.add(new Order("views", SqlKey.DESC));
            }
            orders = generatorOrder(orders);
            queryTable.setOrder(orders);
            DataTable dataTable = articleService.findPage(queryTable);
            records = dataTable.getData();
            for (Article article : records) {
                // 是否已收藏
                boolean hasFavored = articleService.checkFavored(user, article.getArticleId());
                article.setHasFavored(hasFavored);
                // 是否已关注
                boolean hasWatched = articleService.checkWatched(user, Convert.toLong(article.getCreateBy()));
                article.setHasWatched(hasWatched);
            }
            dataTable.setData(records);
            return success(dataTable);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SERVER), e.getMessage());
        }
    }

    @GetMapping("/query/video")
    @ApiOperation(value = "查询视频文章列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "current_page", value = "当前页号"),
            @ApiImplicitParam(name = "page_length", value = "每页数量")
    })
    public AjaxResponse queryVideo(UserDetailDTO userDetail) {
        String channel = "4";
        int currentPage = Convert.toInt(getRequest().getParameter("current_page"), 1);
        int length = Convert.toInt(getRequest().getParameter("page_length"), 15);
        List<Article> records;
        try {
            QueryTable queryTable = new QueryTable();
            queryTable.setCurrentPage(currentPage);
            queryTable.setLength(length);
            queryTable.setStart((queryTable.getCurrentPage() - 1) * queryTable.getLength());
            Map<String, Object> param = new HashMap<>();
            param.put("Q_channel_S_EQ", channel);
            param.put("Q_status_S_EQ", StatusType.NORMAL.getCode());

            // 判断相关权限
            if (userDetail == null) {
                param.put("Q_open_S_EQ", StatusType.VISIBLE.getCode());
                param.put("Q_memberLevel_INT_LE", 1);
            } else {
                SysUserDTO currentUser = (SysUserDTO) userDetail.getDetail();
                UmsMember userMember = umsMemberService.findByUser(currentUser.getUserId());
                param.put("Q_open_S_EQ_AND(group1)", StatusType.HIDDEN.getCode());
                param.put("Q_createBy_L_EQ_AND(group1)", currentUser.getUserId());
                param.put("Q_open_S_EQ_AND(group2)", StatusType.VISIBLE.getCode());
                param.put("Q_memberLevel_INT_LE_AND(group2)", null == userMember ? 1 : Convert.toInt(userMember.getLevelId(), 1));
            }
            queryTable.setParams(param);
            List<Order> orders = new ArrayList<>();
            orders = generatorOrder(orders);
            queryTable.setOrder(orders);
            DataTable dataTable = articleService.findPage(queryTable);
            return success(dataTable);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SERVER), e.getMessage());
        }
    }

    @GetMapping("/query/article/search/{keyword}")
    @ApiOperation(value = "搜索文章列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "current_page", value = "当前页号"),
            @ApiImplicitParam(name = "page_length", value = "每页数量"),
            @ApiImplicitParam(value = "关键词", type = "path")
    })
    public AjaxResponse search(@PathVariable String keyword, UserDetailDTO userDetail) {
        List<Article> records = new ArrayList<>();
        try {
            String title, content;
            Integer memberGrowth;
            SysUserDTO login = new SysUserDTO();
            if (null != userDetail) {
                login = (SysUserDTO) userDetail.getDetail();
            }

            QueryTable queryTable = initTable();
            Map<String, Object> param = new HashMap<>();
            param.put("Q_title_S_LK_OR", keyword);
            param.put("Q_content_S_LK_OR", keyword);
            queryTable.setParams(param);
            queryTable.setEntity(Article.class);
            DataTable<Article> dataTable = EsSearchUtil.getInstance().<Article>searchPage(queryTable, true, true);
            List<Article> results = dataTable.getData();
            int recordTotal = dataTable.getRecordsTotal();

            UmsMember userMember = umsMemberService.findByUser(login.getUserId());
            for (Article article : results) {
                title = article.getTitle();
                content = article.getContent();
                article = articleService.findById(article.getArticleId());
                // 判断相关权限
                if (login.getUserId() != Convert.toLong(article.getCreateBy(), 0L)) {
                    if (StatusType.HIDDEN.getCode().equals(article.getOpen())) {
                        recordTotal--;
                        continue;
                    }

                    memberGrowth = null == userMember ? 0 : Convert.toInt(userMember.getGrowth(), 1);
                    if (memberGrowth < Convert.toLong(article.getMemberGrowth())) {
                        recordTotal--;
                        continue;
                    }
                }
                article.setTitle(title);
                article.setContent(content);
                // 是否已收藏
                boolean hasFavored = articleService.checkFavored(login, article.getArticleId());
                article.setHasFavored(hasFavored);
                // 是否已关注
                boolean hasWatched = articleService.checkWatched(login, Convert.toLong(article.getCreateBy()));
                article.setHasWatched(hasWatched);
                records.add(article);
            }

            dataTable.setData(records);
            dataTable.setRecordsTotal(recordTotal);

            return success(dataTable);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SERVER), e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/saveComment")
    @AclPermission
    @ApiOperation(value = "发表评论")
    @ApiImplicitParam(value = "评论表单", dataTypeClass = ArticleComment.class, type = "body")
    public AjaxResponse saveComment(UserDetailDTO userDetail) {
        try {
            ArticleComment comment = new ArticleComment();
            comment.setCommentUserId(Convert.toLong(userDetail.getId()));
            comment.setTargetUserId(Convert.toLong(getRequest().getParameter("targetUser")));
            comment.setArticleId(Convert.toLong(getRequest().getParameter("articleId")));
            comment.setParentId(Convert.toLong(getRequest().getParameter("parentId"), 0l));
            comment.setContent(getRequest().getParameter("content"));
            comment.setStatus(StatusType.NORMAL.getCode());
            comment.setCreateTime(new Date());
            comment.setCreateBy(Convert.toLong(userDetail.getId()));
            articleCommentService.insert(comment);
            Article article = articleService.findById(Convert.toLong(getRequest().getParameter("articleId")));
            if (null != article) {
                articleService.onPushEvent(article, ArticlePostEvent.ACTION_COMMENT);
            }
            return success(I18nUtil.message(ExceptionConstants.SAVE_SUCCESS));
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SAVE_FAILURE), e.getMessage());
        }
    }

    private List<Order> generatorOrder(List<Order> orders) {
        if (null == orders) {
            orders = new ArrayList<>();
        }
        orders.add(new Order("featured", SqlKey.ASC));
        orders.add(new Order("weight", SqlKey.ASC));
        orders.add(new Order("group", SqlKey.ASC));
        orders.add(new Order("groupIndex", SqlKey.ASC));
        orders.add(new Order("createTime", SqlKey.DESC));
        return orders;
    }
}
